package org.study.util;

import java.io.*;

/**
 * https://www.jb51.net/article/105293.htm
 *
 * @author Administrator
 * @date 2021-11-22
 */
public class ReadFileTests01 {
    public static void main(String[] args) {
        String fileName = "E:/data/20211123-test.bin";
        ReadFileTests01.readFileByByte(fileName);
        ReadFileTests01.readFileByChar(fileName);
        ReadFileTests01.readFileByLine(fileName);
        ReadFileTests01.readFileByRandomAccess(fileName);
    }

    /**
     * 以字节为单位读取文件，常用于读二进制文件，如图片、声音、影像等文件
     */
    public static void readFileByByte(String fileName) {
        System.out.println("\n========== 以字节为单位读取文件内容 ==========");
        File file = new File(fileName);
        long length = file.length();

        System.out.println("【一次读一个字节】");
        try (FileInputStream fis = new FileInputStream(file)) {
            // 一次读一个字节
            System.out.println("当前字节输入流中还剩的字节数为：" + fis.available());
            int tmpByte;
            while ((tmpByte = fis.read()) != -1) {
                System.out.write(tmpByte);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("【一次读多个字节】");
        try (FileInputStream fis = new FileInputStream(fileName)) {
            // 一次读多个字节
            byte[] tmpBytes = new byte[1024];
            int byteRead = 0;
            System.out.println("当前字节输入流中还剩的字节数为：" + fis.available());
            // 读入多个字节到字节数组中，byteRead 为一次读入的字节数
            while ((byteRead = fis.read(tmpBytes)) != -1) {
                System.out.write(tmpBytes, 0, byteRead);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 以字符为单位读取文件，常用于读文本，数字等类型的文件
     */
    public static void readFileByChar(String fileName) {
        System.out.println("\n========== 以字符为单位读取文件内容 ==========");
        File file = new File(fileName);
        long length = file.length();

        System.out.println("【一次读一个字节】");
        try (FileInputStream fis = new FileInputStream(file);
             Reader reader = new InputStreamReader(fis)) {
            System.out.println("当前字节输入流中还剩的字节数为：" + fis.available());
            // 一次读一个字符
            int tmpChar;
            while ((tmpChar = reader.read()) != -1) {
                // 对于windows下，\r\n这两个字符在一起时，表示一个换行
                // 但如果这两个字符分开显示时，会换两次行
                // 因此，屏蔽掉\r，或者屏蔽\n。否则，将会多出很多空行
                if (((char) tmpChar) != '\r') {
                    System.out.print((char) tmpChar);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("【一次读多个字节】");
        try (FileInputStream fis = new FileInputStream(fileName);
             Reader reader = new InputStreamReader(fis)) {
            System.out.println("当前字节输入流中还剩的字节数为：" + fis.available());
            // 一次读多个字符
            char[] tmpChars = new char[128];
            int charRead = 0;
            // 读入多个字符到字符数组中，charRead 为一次读取字符数
            while ((charRead = reader.read(tmpChars)) != -1) {
                // 同样屏蔽掉\r不显示
                if ((charRead == tmpChars.length) && (tmpChars[tmpChars.length - 1] != '\r')) {
                    System.out.print(tmpChars);
                } else {
                    for (int i = 0; i < charRead; i++) {
                        if (tmpChars[i] == '\r') {
                            continue;
                        } else {
                            System.out.print(tmpChars[i]);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 以行为单位读取文件，常用于读面向行的格式化文件
     */
    public static void readFileByLine(String fileName) {
        System.out.println("\n========== 以行为单位读取文件内容 ==========");
        File file = new File(fileName);
        long length = file.length();

        System.out.println("【一次读一整行】");
        try (FileReader fr = new FileReader(file);
             BufferedReader reader = new BufferedReader(fr)) {
            String tmpStr = null;
            int line = 1;
            // 一次读入一行，直到读入 null 为文件结束
            while ((tmpStr = reader.readLine()) != null) {
                // 显示行号
                System.out.println("line " + line + "： " + tmpStr);
                line++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 随机读取文件内容
     */
    public static void readFileByRandomAccess(String fileName) {
        System.out.println("\n========== 随机读取一段文件内容 ==========");
        File file = new File(fileName);
        long length = file.length();

        try (RandomAccessFile randomFile = new RandomAccessFile(file, "r")) {
            //try (RandomAccessFile randomFile = new RandomAccessFile(fileName, "r")) {
            // 打开一个随机访问文件流，按只读方式
            // 文件长度，字节数
            long fileLength = randomFile.length();
            // 读文件的起始位置
            int beginIndex = 0;
            //int beginIndex = (fileLength > 4) ? 4 : 0;
            // 将读文件的开始位置移到 beginIndex 位置
            randomFile.seek(beginIndex);
            byte[] bytes = new byte[10];
            int byteRead = 0;
            // 一次读10个字节，如果文件内容不足10个字节，则读剩下的字节。
            // 将一次读取的字节数赋给 byteRead
            while ((byteRead = randomFile.read(bytes)) != -1) {
                System.out.write(bytes, 0, byteRead);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
